home *** CD-ROM | disk | FTP | other *** search
- #ifndef THINK_C
- #include <Memory.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <TextEdit.h>
- #include <OSEvents.h>
- #include <Dialogs.h>
- #include <Packages.h>
- #include <ToolUtils.h>
- #include <Desk.h>
- #include <ThreadUtil.h>
- #include <GestaltEqu.h>
- #include <Types.h>
- #include <QDOffscreen.h>
- #endif
-
- #include "ProtoStructs.h"
-
- /***********************************************************************************
- **
- ** Almighty global declarations
- **
- */
- short gDone, gInBackground;
- philoRecord gPhilosophizer[kNumOfPhilosophizers];
- CIconHandle gNoForkIcon, gLeftForkIcon, gBothForksIcon;
- SimpleSemaphorePtr gForks[kNumOfPhilosophizers];
- GWorldPtr gOffscreenWorld;
-
-
- /***********************************************************************************
- **
- ** Make sure that this machine has ColorQD and the Thread Mgr.
- */
- void system_attrib()
- {
- long res;
- short comparebit;
- OSErr returnErr;
-
- returnErr = Gestalt (gestaltQuickdrawVersion, &res);
-
- if ( returnErr != noErr )
- error("\pProblem with Gestalt in system_attrib", returnErr, kFatal);
-
- comparebit = gestaltOriginalQD;
-
- if (BitTst(&res, 31 - comparebit) == TRUE)
- error("\pSorry, you need Color QuickDraw to run.", returnErr, kFatal);
-
- returnErr = Gestalt (gestaltThreadMgrAttr, &res);
-
- if ( returnErr != noErr )
- if ( returnErr == gestaltUndefSelectorErr )
- error("\pSorry, you gotta have >>THREADS<< (The Thread Manager)",
- returnErr,
- kFatal);
- else
- error("\pProblem with Gestalt in sys_attrib", returnErr, kFatal);
-
- comparebit = gestaltThreadMgrPresent;
-
- if (BitTst(&res, 31 - comparebit) == FALSE) /* If Thread Mgr isn't loaded */
- error("\pSorry, you gotta have >>THREADS<< (The Thread Manager)",
- returnErr,
- kFatal);
-
- }
-
-
- /***********************************************************************************
- **
- ** I put the MaxAppleZone() call out here, to make sure
- ** that it is called first.
- */
- void main()
- {
- WindowPtr appWindow;
- MaxApplZone();
-
- init_mac();
- InitializeThreadUtilities();
- init_threads();
-
- appWindow = init_rooms();
- init_philosophizers(appWindow);
- spawn_threads();
- event_loop();
- }
-
-
- /***********************************************************************************
- **
- ** A general purpose error display routine that works with two ALRT resources.
- */
- void error(Str255 err_string, short err_val, short fatal)
- {
- Str255 num_string = "\p";
-
- NumToString((long)err_val, num_string);
- ParamText(err_string, num_string, 0, 0);
-
- if ( fatal )
- {
- (void)Alert(kErrorAlert, nil);
- ExitToShell();
- }
- else
- (void)Alert(kErrorAlert, nil);
- }
-
-
- /***********************************************************************************
- **
- ** It's a DA window if the windowKind field is less than 0
- */
- short is_DA_window(WindowPtr win)
- {
- if ( (win == nil) || ((*(WindowPeek)win).windowKind >= 0) )
- return(FALSE);
- else
- return(TRUE);
- }
-
-
- /***********************************************************************************
- **
- ** Standard Macintosh application initialization.
- */
- void init_mac()
- {
-
- #ifndef THINK_C
- InitGraf(&qd.thePort);
- #else
- InitGraf(&thePort);
- #endif
- InitFonts();
- InitWindows();
- InitMenus();
- InitCursor();
- TEInit(); // To make sure that DAs, dialogs and alerts work OK
- FlushEvents(everyEvent, 0);
- InitDialogs(0L);
- system_attrib(); // Check up on this Mac's attributes.
- SetMenuBar(GetNewMBar(128));
- AddResMenu(GetMHandle(kAppleMenu), 'DRVR');
- DrawMenuBar();
-
- gDone = FALSE;
- gInBackground = FALSE;
-
- gNoForkIcon = GetCIcon(kNoForkIcon);
- gLeftForkIcon = GetCIcon(kLeftForkIcon);
- gBothForksIcon = GetCIcon(kBothForksIcon);
- }
-
-
- /***********************************************************************************
- **
- ** Set up each philosopizer's icon locations and initial state.
- */
- void init_philosophizers(WindowPtr win)
- {
- short index;
-
- for ( index = 0; index < kNumOfPhilosophizers; index++ )
- {
- /* Thinking locations */
- gPhilosophizer[index].thinking_location.top =
- win->portRect.top + kIconOffset + (kIconDimension * index) +
- (kIconOffset * index);
- gPhilosophizer[index].thinking_location.bottom =
- gPhilosophizer[index].thinking_location.top + kIconDimension;
- gPhilosophizer[index].thinking_location.left =
- win->portRect.right - (kIconOffset + kIconDimension);
- gPhilosophizer[index].thinking_location.right =
- gPhilosophizer[index].thinking_location.left + kIconDimension;
-
- /* Waiting locations */
- gPhilosophizer[index].waiting_location.top = gPhilosophizer[index].thinking_location.top;
- gPhilosophizer[index].waiting_location.bottom = gPhilosophizer[index].waiting_location.top + kIconDimension;
- gPhilosophizer[index].waiting_location.left = gPhilosophizer[index].thinking_location.left - 150;
- gPhilosophizer[index].waiting_location.right = gPhilosophizer[index].waiting_location.left + kIconDimension;
-
-
- /* Dining locations */
- gPhilosophizer[index].dining_location.top =
- win->portRect.top + kIconOffset + (kIconDimension * index) +
- (kIconOffset * index);
- gPhilosophizer[index].dining_location.bottom =
- gPhilosophizer[index].thinking_location.top + kIconDimension;
- gPhilosophizer[index].dining_location.left =
- win->portRect.left + kIconOffset;
- gPhilosophizer[index].dining_location.right =
- gPhilosophizer[index].dining_location.left + kIconDimension;
-
- gPhilosophizer[index].left_fork = index;
-
- /* Philo's initial attributes */
- gPhilosophizer[index].fork_state = kNoForks;
- gPhilosophizer[index].current_location = gPhilosophizer[index].thinking_location;
- }
- }
-
-
- /***********************************************************************************
- **
- ** You can create Preemptive threads right here, just make sure to change what's
- ** in spawn_threads, too.
- */
- void init_threads()
- {
- OSErr anError;
-
- /* Make a pool of threads for the Philos */
- anError = CreateThreadPool(kCooperativeThread, kNumOfPhilosophizers, (Size)0);
- if ( anError )
- error ("\pProblem creating thread pool", anError, kFatal);
-
- /* Make a Footman (to prevent deadlock) */
- create_footman();
-
- /* Make the forks (an array of SimpleSemaphores) */
- create_forks();
- }
-
-
- /***********************************************************************************
- **
- ** Set up the offscreen GWorld, for those fast updates
- */
- WindowPtr init_rooms()
- {
- QDErr anError;
- WindowPtr new_window;
- Rect win_rect = {50, 50, 300, 500};
-
- /*
- ** First draw the new window
- */
- new_window = NewCWindow(nil, &win_rect,
- "\pDining Philosophizers", FALSE,
- noGrowDocProc, (WindowPtr)-1,
- TRUE, 0L);
- ShowWindow(new_window);
-
- anError = NewGWorld(&gOffscreenWorld,
- 0,
- &new_window->portRect,
- nil,
- nil,
- keepLocal);
-
- if (anError)
- error("\pCouldn't create the GWorld", anError, kFatal);
-
- return new_window;
- }
-
-
- /***********************************************************************************
- **
- ** Takes the result from a menu call (either from keys or the mouse) and figures out
- ** where to go.
- */
- void menu_command(long result)
- {
- short menu_ID, item_num;
-
- menu_ID = HiWord(result);
- item_num = LoWord(result);
-
- switch( menu_ID )
- {
- case kAppleMenu:
- HiliteMenu(kAppleMenu);
- do_apple_menu(item_num);
- break;
-
- case kFileMenu:
- HiliteMenu(kFileMenu);
- switch( item_num )
- {
- case kQuitItem: gDone = TRUE; break;
- }
- break;
- }
- HiliteMenu(0);
- }
-
-
- /***********************************************************************************
- **
- ** Called by menu_command().
- */
- void do_apple_menu(short item)
- {
- Str255 da_name;
- GrafPtr orig_port;
-
- if ( item == kAboutItem )
- (void)Alert(kAboutThisApp,nil);
- else
- {
- GetItem(GetMHandle(kAppleMenu), item, da_name);
- GetPort(&orig_port);
- OpenDeskAcc(da_name);
- SetPort(orig_port);
- }
- }
-
-
- /***********************************************************************************
- **
- ** The Philosophizers are updated at every null event
- */
- void event_loop()
- {
- EventRecord my_evt;
- short got_evt = 0;
- OSErr anError;
- WindowPtr win;
-
- while( !gDone )
- {
- ThreadBeginCritical();
-
- got_evt = WaitNextEvent(everyEvent, &my_evt, kSleepTicks, nil);
-
- if ( got_evt )
- {
- switch( my_evt.what )
- {
- case nullEvent: break;
- case mouseDown: mousedown_evt(my_evt); break;
- case mouseUp: break;
- case keyDown: keydown_evt(my_evt); break;
- case keyUp: break;
- case autoKey: break;
- case updateEvt: update_evt(my_evt); break;
- case diskEvt: break;
- case activateEvt: break;
- case networkEvt: break;
- case driverEvt: break;
- case app1Evt: break;
- case app2Evt: break;
- case app3Evt: break;
- case app4Evt: suspend_resume_evt(my_evt); break;
- default : break;
- }
- }
- else
- {
- win = FrontWindow();
- if ( !is_DA_window(win) && (!gInBackground) )
- draw_and_slam(win);
- }
-
- ThreadEndCritical();
-
- anError = YieldToAnyThread();
- if ( anError )
- error ("\pError in yielding the main thread", anError, kFatal);
- }
- /* Shutdown routines */
- remove_forks();
- retire_footman();
- }
-
-
- /***********************************************************************************
- **
- ** Sets the background global, and draws the grow icon.
- */
- void suspend_resume_evt(EventRecord event)
- {
- if ( event.message & 0x01000000 ) /* Is it a suspend or resume? */
- {
- if ( event.message & 0x00000001 ) /* Is it a resume event? */
- gInBackground = FALSE;
- else /* It's a suspend event */
- gInBackground = TRUE;
-
- }
- }
-
-
- /***********************************************************************************
- **
- ** Handle keyboard events by eventually calling menu_command.
- */
- void keydown_evt(EventRecord event)
- {
- char key;
- long result;
-
- key = event.message & charCodeMask;
-
- if ( (event.modifiers & cmdKey) != 0 )
- {
- result = MenuKey(key);
- if ( HiWord(result) != 0 ) /* Is it a valid key? */
- menu_command(result);
- }
- else
- SysBeep(3); /* It's a normal keystroke, just beep */
-
- }
-
-
- /***********************************************************************************
- **
- ** Handle mouse down events
- */
- void mousedown_evt(EventRecord event)
- {
- WindowPtr win;
- long result;
- Point mouse_point;
- GrafPtr orig_port;
- short ret_val;
-
- ret_val = FindWindow(event.where, &win);
-
- switch ( ret_val )
- {
- case inDesk: break;
- case inMenuBar:
- result = MenuSelect(event.where);
- if ( HiWord(result) != 0 )
- menu_command(result);
- break;
-
- case inSysWindow: break;
-
- case inContent:
- GetPort(&orig_port);
- SetPort(win);
-
- mouse_point = event.where;
- GlobalToLocal(&mouse_point);
-
- if ( win != FrontWindow() )
- SelectWindow(win);
-
- SetPort(orig_port);
- break;
-
- case inDrag:
- #ifndef THINK_C
- DragWindow(win, event.where, &qd.screenBits.bounds);
- #else
- DragWindow(win, event.where, &screenBits.bounds);
- #endif
- break;
-
- case inGrow:
- break;
-
- case inGoAway:
- if ( TrackGoAway(win, event.where) )
- gDone = TRUE;
- break;
-
- case inZoomIn: break;
- case inZoomOut: break;
- }
- }
-
-
- /***********************************************************************************
- **
- ** Update the content rect of the window, set the clip rgn to this content rect,
- ** draw the tools, and reset the clip rgn to normal.
- */
- void update_evt(EventRecord event)
- {
- GrafPtr orig_port;
- WindowPtr update_win;
-
- update_win = (WindowPtr)event.message;
- GetPort(&orig_port);
- SetPort(update_win);
-
-
- BeginUpdate(update_win);
- draw_and_slam(update_win);
- EndUpdate(update_win);
-
- SetPort(orig_port);
- }
-
-
- /***********************************************************************************
- **
- ** Get PICT 128 and draw it to the current GrafPort
- */
- void draw_background(WindowPtr win)
- {
- PicHandle ph = GetPicture(kPictID);
- DrawPicture(ph, &win->portRect);
- }
-
-
- /***********************************************************************************
- **
- ** Draw it according to its fork state (three different icons.
- */
- void draw_philosophizers(WindowPtr win)
- {
- short index;
-
- SetPort(win);
- for ( index = 0; index < kNumOfPhilosophizers; index++ )
- {
- switch ( gPhilosophizer[index].fork_state )
- {
- case kNoForks :
- PlotCIcon(&(gPhilosophizer[index].current_location), gNoForkIcon);
- break;
-
- case kLeftFork :
- PlotCIcon(&(gPhilosophizer[index].current_location), gLeftForkIcon);
- break;
-
- case kBothForks :
- PlotCIcon(&(gPhilosophizer[index].current_location), gBothForksIcon);
- break;
- }
- }
- }
-
-
- /***********************************************************************************
- **
- ** The name says it all
- */
- void draw_and_slam(WindowPtr win)
- {
- GrafPtr old_port;
-
- GetPort(&old_port);
- SetPort((WindowPtr)gOffscreenWorld);
-
- LockPixels(gOffscreenWorld->portPixMap);
- draw_background((WindowPtr)gOffscreenWorld);
- draw_philosophizers((WindowPtr)gOffscreenWorld);
- UnlockPixels(gOffscreenWorld->portPixMap);
-
- SetPort(win);
-
- HLock((Handle)(gOffscreenWorld->portPixMap));
-
- CopyBits((const BitMap *)*(gOffscreenWorld->portPixMap),
- (const BitMap *)&(win->portBits),
- &gOffscreenWorld->portRect,
- &(win->portRect),
- srcCopy,
- nil);
-
- HUnlock((Handle)(gOffscreenWorld->portPixMap));
-
- SetPort(old_port);
- }
-
-